﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Physis.Security {

    public class SecurityAuthority : Core.CoreConfigurationObject {

        #region Private Properties

        private Enumerations.SecurityAuthorityType securityAuthorityType = Enumerations.SecurityAuthorityType.WindowsIntegrated;

        private String protocol = String.Empty; // RESERVED FOR FUTURE USE  

        private String serverName = String.Empty; // RESERVED FOR FUTURE USE 

        private String domain = String.Empty; 


        // INITIAL IS ONLY SUPPORTING WINDOWS INTEGRATED

        // TO SUPPORT LDAP (AND ACTIVE DIRECTORY), WE MIGHT NEED TO SUPPORT 

        // AGENT NAME/PASSWORD FOR AUTHENTICATING AGAINST THE DIRECTORY

        // FOR CUSTOM PROVIDERS, WE NEED TO SUPPORT SECURITY PROVIDER DYNAMIC LOADING 

        // THIS MEANS ASSEMBLY PATH/NAME NAMESPACE/CLASS THAT IMPLEMENTS ISECURITYPROVIDER

        // THIS WOULD ALL BE FUTURE SUPPORT IF REQUIRED

        #endregion 


        #region Public Properties

        public Enumerations.SecurityAuthorityType SecurityAuthorityType { get { return securityAuthorityType; } set { securityAuthorityType = value; } }

        public String SecurityAuthorityTypeDescription { get { return Data.Functions.PascalString (securityAuthorityType.ToString ()); } }

        public String Protocol { get { return protocol; } set { protocol = Data.Functions.SetValueMaxLength (value, 60); } }

        public String ServerName { get { return serverName; } set { serverName = Data.Functions.SetValueMaxLength (value, 60); } }

        public String Domain { get { return domain; } set { domain = Data.Functions.SetValueMaxLength (value, 60); } }

        #endregion 

        
        #region Constructors

        public SecurityAuthority (Application forApplication) : base (forApplication) {

            return;

        }

        public SecurityAuthority (Application forApplication, Int64 forId) : base (forApplication) {

            if (!Load (forId, Application.EnterpriseDatabase)) {

                throw new Exception (GetType ().FullName + ".Load [Failed]: " + forId);

            }

            return;

        }

        public SecurityAuthority (Application forApplication, Enumerations.SecurityAuthorityType forSecurityAuthorityType, String forDomain) : base (forApplication) {

            // USED TO LOAD A SECURITY AUTHORITY BY TYPE AND DOMAIN NAME 

            String selectStatement = String.Empty;
            
            selectStatement += "SELECT * FROM " + ObjectType;

            selectStatement += "  WHERE SecurityAuthorityType = " + ((Int32) forSecurityAuthorityType).ToString ();

            selectStatement += "    AND Domain = '" + forDomain.Replace ("'", "''") + "'";

            if (!LoadFromDatabase (selectStatement, Application.EnterpriseDatabase)) {

                throw new Exception (GetType ().FullName + ".Load [Failed]: " + forSecurityAuthorityType + "." + forDomain);

            }

            return;

        }

        #endregion


        #region Data Functions 

        protected override Dictionary<String, String> Validate () {

            Dictionary<String, String> validationErrors = base.Validate ();


            if (String.IsNullOrWhiteSpace (Domain)) { validationErrors.Add ("Domain", "Empty or invalid value for Domain."); }


            return validationErrors;

        }

        public override void MapDataFields (System.Data.DataRow currentRow) {

            base.MapDataFields (currentRow);

            
            SecurityAuthorityType = (Enumerations.SecurityAuthorityType)Data.Readers.DataReader.Int32FromDatabase (currentRow, "SecurityAuthorityType");

            Protocol = Data.Readers.DataReader.StringFromDatabase (currentRow, "Protocol");

            ServerName = Data.Readers.DataReader.StringFromDatabase (currentRow, "ServerName");

            Domain = Data.Readers.DataReader.StringFromDatabase (currentRow, "Domain"); 


            return;

        }

        public override Boolean Save () {

            Boolean success = false;

            try {

                Dictionary<String, String> validationErrors = Validate ();

                if (validationErrors.Count > 0) {

                    Application.SetLastException (new Exception ("Invalid [" + validationErrors.Keys.First() + "]: " + validationErrors.Values.First()));

                    return false;

                }

                UpdateModifiedToSessionUser ();


                System.Data.IDbCommand command = Application.EnterpriseDatabase.CreateCommand (ObjectType + "_InsertUpdate");

                command.CommandType = System.Data.CommandType.StoredProcedure;


                Application.EnterpriseDatabase.AppendCommandParameter (command, "Id", Id);

                Application.EnterpriseDatabase.AppendCommandParameter (command, "Name", Name, 60);

                Application.EnterpriseDatabase.AppendCommandParameter (command, "Description", Description, 999);


                Application.EnterpriseDatabase.AppendCommandParameter (command, "SecurityAuthorityType", ((Int32)SecurityAuthorityType));

                Application.EnterpriseDatabase.AppendCommandParameter (command, "Protocol", Protocol, 60);

                Application.EnterpriseDatabase.AppendCommandParameter (command, "ServerName", ServerName, 60);

                Application.EnterpriseDatabase.AppendCommandParameter (command, "Domain", Domain, 60);


                Application.EnterpriseDatabase.AppendCommandParameter (command, "ModifiedId", Application.Session.UserAccountName, 60);

                success = (command.ExecuteNonQuery () > 0);

                if (success) { SetIdentity (Application.EnterpriseDatabase); }

            }

            catch (Exception exception) {

                success = false;

                Application.SetLastException (exception);

            }

            return success; 

        }

        public override Boolean Delete () {

            return base.DeleteFromDatabase (DeleteStatementById (), Application.EnterpriseDatabase);

        }

        #endregion 


        #region Public Methods 

        public List<DirectoryEntryHelper> Users () {

            // TODO: IMPROVE THIS TO SUPPORT MULTIPLE PROVIDER TYPES IN THE FUTURE 

            // IT SOULD PROBABLY REFERENCE THE APPLICATION TO GET THE APPROPRIATE PROVIDER TYPE (MAYBE) 

            ISecurityProvider provider = new Providers.WindowsIntegrated ();

            return provider.Users (domain, serverName);

        }

        #endregion 

    }

}
